/*
 * Copyright 2013 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package io.netty.util;

import io.netty.util.concurrent.FastThreadLocal;
import io.netty.util.internal.SystemPropertyUtil;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import static io.netty.util.internal.MathUtil.safeFindNextPositivePowerOfTwo;
import static java.lang.Math.max;
import static java.lang.Math.min;

/**
 * 1.基于线程本地堆栈的轻量级对象池
 * 2.对象池是对于线程而言的，每个线程都有自己的对象缓存，也就是对象池
 * 3.对象池实际上就是每一个线程的本地栈，也就是stack
 * Recycler这个类在我看来，这个类只不过是每个线程从各自对象池中获取对象的入口。由该类的方法得到FastThreadLocal，然后得到本地线程的map，每个线程的stack就存储在这个ThreadLocal中
 *
 * @param <T> 集合对象的类型
 */
public abstract class Recycler<T> {
    /**
     * 日志没啥好看的
     */
    private static final InternalLogger logger = InternalLoggerFactory.getInstance(Recycler.class);
    /**
     * 空实现的Handle
     */
    @SuppressWarnings("rawtypes")
    private static final Handle NOOP_HANDLE = object -> {
    };
    /**
     * 该属性是用来给线程提供特殊化id的，这个id是给生产对象的线程和回收对象的线程赋值的
     */
    private static final AtomicInteger ID_GENERATOR = new AtomicInteger(Integer.MIN_VALUE);

    private static final int OWN_THREAD_ID = ID_GENERATOR.getAndIncrement();
    /**
     * 每一个线程对应的stack可以存储的数据的最大个数，stack存储数据的是一个数组容器，默认最大容量为4096
     * 毕竟对象池不能无限扩大
     */
    private static final int DEFAULT_INITIAL_MAX_CAPACITY_PER_THREAD = 4 * 1024;
    /**
     * 这个属性就是stack最大的容量，上面的属性最后会赋值给它
     */
    private static final int DEFAULT_MAX_CAPACITY_PER_THREAD;
    /**
     * stack默认的初始化容量为256个
     */
    private static final int INITIAL_CAPACITY;
    /**
     * 这是一个辅助属性，帮助计算所有帮忙回收对象的线程能够为原来获取对象的线程能够回收的对象的最大值
     * 这个也是在限制对象池的容量，不能让它无限扩大，默认值为2
     */
    private static final int MAX_SHARED_CAPACITY_FACTOR;
    /**
     * 每一个线程最多可以帮助几个线程回收对象。默认值是cpu的核数乘以2
     * 其实就是默认的工作组线程的数量，这个数值在Netty中用得比较多，内存池的时候也会用到，那里其实就是为了让每一个线程都能参与进来
     */
    private static final int MAX_DELAYED_QUEUES_PER_THREAD;
    /**
     * link链表中每一个link节点使用数组存储待回收的对象，这个数组的默认容量为16
     * 存储满了就找下一个link节点，不会扩容
     */
    private static final int LINK_CAPACITY;
    /**
     * 对象被回收的比例。默认是8比1。比如一个线程从对象池也就是它的本地stack中得到了8个对象，那么就把第8个对象回收进来
     * 这里也是为了防止对象池无限膨胀。大家现在可能觉得能创建多少对象啊，至于这么限制吗？
     * 但是想一想，Netty中所有数据的处理都离不开ByteBuf这个对象。成百上千个客户端发送数据的时候要创建的ByteBuf多了去了
     * 这个对象就要从对象池中获得，如果每一个都被回收，那对象池就会把内存占满了。
     */
    private static final int RATIO;
    /**
     * 线程的stack中数组的最大容量，实际上就是对象池的最大容量4096
     */
    private final int maxCapacityPerThread;
    /**
     * 这个属性就是帮助计算所有帮忙回收对象的线程能够为原来获取对象的线程能够回收的对象的最大值
     */
    private final int maxSharedCapacityFactor;
    /**
     * 这个就是每个线程回收自身对象的比例
     */
    private final int ratioMask;
    /**
     * 每个线程最多可以帮助几个线程回收它们的对象
     */
    private final int maxDelayedQueuesPerThread;
    /**
     * 线程本地存储Stack也就是对象池
     */
    private final FastThreadLocal<Stack<T>> threadLocal = new FastThreadLocal<Stack<T>>() {
        @Override
        protected Stack<T> initialValue() {
            return new Stack<T>(Recycler.this, Thread.currentThread(), maxCapacityPerThread, maxSharedCapacityFactor,
                    ratioMask, maxDelayedQueuesPerThread);
        }

        @Override
        protected void onRemoval(Stack<T> value) {
            // Let us remove the WeakOrderQueue from the WeakHashMap directly if its safe to remove some overhead
            if (value.threadRef.get() == Thread.currentThread()) {
                if (DELAYED_RECYCLED.isSet()) {
                    DELAYED_RECYCLED.get().remove(value);
                }
            }
        }
    };

    private static final FastThreadLocal<Map<Stack<?>, WeakOrderQueue>> DELAYED_RECYCLED =
            new FastThreadLocal<Map<Stack<?>, WeakOrderQueue>>() {
                @Override
                protected Map<Stack<?>, WeakOrderQueue> initialValue() {
                    return new WeakHashMap<>();
                }
            };

    static {
        // 这个就是stack中数组最大容量的赋值
        int maxCapacityPerThread = SystemPropertyUtil.getInt("io.netty.recycler.maxCapacityPerThread",
                SystemPropertyUtil.getInt("io.netty.recycler.maxCapacity", DEFAULT_INITIAL_MAX_CAPACITY_PER_THREAD));
        if (maxCapacityPerThread < 0) {
            maxCapacityPerThread = DEFAULT_INITIAL_MAX_CAPACITY_PER_THREAD;
        }
        // maxCapacityPerThread又赋值给了该属性
        DEFAULT_MAX_CAPACITY_PER_THREAD = maxCapacityPerThread;
        // 这个就是我们之前说的那个辅助的属性，默认值为2，帮助计算每个线程最多可以帮助其他线程回收多少个对象
        MAX_SHARED_CAPACITY_FACTOR = max(2,
                SystemPropertyUtil.getInt("io.netty.recycler.maxSharedCapacityFactor",
                        2));
        // 每一个线程最多可以帮助几个线程回收对象。默认值是cpu的核数乘以2
        MAX_DELAYED_QUEUES_PER_THREAD = max(0,
                SystemPropertyUtil.getInt("io.netty.recycler.maxDelayedQueuesPerThread",
                        NettyRuntime.availableProcessors() * 2));
        // link链表中每一个link节点使用数组存储待回收的对象，这个数组的默认容量为16
        LINK_CAPACITY = safeFindNextPositivePowerOfTwo(
                max(SystemPropertyUtil.getInt("io.netty.recycler.linkCapacity", 16), 16));

        // 对象被回收的比例。默认是8比1。
        RATIO = safeFindNextPositivePowerOfTwo(SystemPropertyUtil.getInt("io.netty.recycler.ratio", 8));

        if (logger.isDebugEnabled()) {
            if (DEFAULT_MAX_CAPACITY_PER_THREAD == 0) {
                logger.debug("-Dio.netty.recycler.maxCapacityPerThread: disabled");
                logger.debug("-Dio.netty.recycler.maxSharedCapacityFactor: disabled");
                logger.debug("-Dio.netty.recycler.linkCapacity: disabled");
                logger.debug("-Dio.netty.recycler.ratio: disabled");
            } else {
                logger.debug("-Dio.netty.recycler.maxCapacityPerThread: {}", DEFAULT_MAX_CAPACITY_PER_THREAD);
                logger.debug("-Dio.netty.recycler.maxSharedCapacityFactor: {}", MAX_SHARED_CAPACITY_FACTOR);
                logger.debug("-Dio.netty.recycler.linkCapacity: {}", LINK_CAPACITY);
                logger.debug("-Dio.netty.recycler.ratio: {}", RATIO);
            }
        }
        // stack中的数组默认的初始容量，为256个，如果存储的属性不够了就要扩容
        // 默认最大容量为4096，毕竟对象池不能无限扩。
        INITIAL_CAPACITY = min(DEFAULT_MAX_CAPACITY_PER_THREAD, 256);
    }

    protected Recycler() {
        this(DEFAULT_MAX_CAPACITY_PER_THREAD);
    }

    protected Recycler(int maxCapacityPerThread) {
        this(maxCapacityPerThread, MAX_SHARED_CAPACITY_FACTOR);
    }

    protected Recycler(int maxCapacityPerThread, int maxSharedCapacityFactor) {
        this(maxCapacityPerThread, maxSharedCapacityFactor, RATIO, MAX_DELAYED_QUEUES_PER_THREAD);
    }

    protected Recycler(int maxCapacityPerThread, int maxSharedCapacityFactor,
                       int ratio, int maxDelayedQueuesPerThread) {
        ratioMask = safeFindNextPositivePowerOfTwo(ratio) - 1;
        if (maxCapacityPerThread <= 0) {
            this.maxCapacityPerThread = 0;
            this.maxSharedCapacityFactor = 1;
            this.maxDelayedQueuesPerThread = 0;
        } else {
            this.maxCapacityPerThread = maxCapacityPerThread;
            this.maxSharedCapacityFactor = max(1, maxSharedCapacityFactor);
            this.maxDelayedQueuesPerThread = max(0, maxDelayedQueuesPerThread);
        }
    }

    @SuppressWarnings("unchecked")
    public final T get() {
        // 如果对象池容量是0则不会池化，而是直接返回对象
        if (maxCapacityPerThread == 0) {
            return newObject((Handle<T>) NOOP_HANDLE);
        }
        // 从FastThreadLocal中获取当前线程的Stack也就是对象池
        Stack<T> stack = threadLocal.get();
        // 弹出一个对象
        DefaultHandle<T> handle = stack.pop();
        // 如果没有
        if (handle == null) {
            // 创建一个Handle
            handle = stack.newHandle();
            // 创建对象然后赋值给属性
            handle.value = newObject(handle);
        }
        return (T) handle.value;
    }

    /**
     * @deprecated use {@link Handle#recycle(Object)}.
     */
    @Deprecated
    public final boolean recycle(T o, Handle<T> handle) {
        if (handle == NOOP_HANDLE) {
            return false;
        }

        DefaultHandle<T> h = (DefaultHandle<T>) handle;
        if (h.stack.parent != this) {
            return false;
        }

        h.recycle(o);
        return true;
    }

    final int threadLocalCapacity() {
        return threadLocal.get().elements.length;
    }

    final int threadLocalSize() {
        return threadLocal.get().size;
    }

    protected abstract T newObject(Handle<T> handle);

    public interface Handle<T> {
        /**
         * 释放对象，释放无外乎就是放回到Stack中
         *
         * @param object
         */
        void recycle(T object);
    }

    static final class DefaultHandle<T> implements Handle<T> {
        /**
         * 就是当前对象可能会被其他线程获得，然后其他线程负责回收工作，这个属性用来记载帮助回收对象的那个线程
         */
        private int lastRecycledId;
        /**
         * 对应获得对象的那个线程
         */
        private int recycleId;
        /**
         * 是否已经回收：
         * 默认false：没有被回收
         * true：已经被回收
         */
        boolean hasBeenRecycled;
        /**
         * 对象池
         */
        private Stack<?> stack;
        /**
         * 被包装的对象
         */
        private Object value;

        DefaultHandle(Stack<?> stack) {
            this.stack = stack;
        }

        @Override
        public void recycle(Object object) {
            // 参数判断
            if (object != value) {
                throw new IllegalArgumentException("object does not belong to handle");
            }
            // 获得对象池
            Stack<?> stack = this.stack;
            if (lastRecycledId != recycleId || stack == null) {
                throw new IllegalStateException("recycled already");
            }
            // 放回到对象池
            stack.push(this);
        }
    }


    private static final class WeakOrderQueue {

        static final WeakOrderQueue DUMMY = new WeakOrderQueue();
        /**
         * WeakOrderQueue对象中的head节点，头节点中指向了下一个link节点。链表从head节点内部开始了
         * 这个head节点中的link指针指向的下一个link节点，就是转移对象时最先被查找的节点
         * 用一句话概括就是，link节点的插入采用的是尾插法，而转移link节点数组中存储的对象，采用的是头查法，从头节点开始查找
         * 用这种方式避开了并发的情况
         */
        private final Head head;
        /**
         * WeakOrderQueue对象中link链表的尾节点
         */
        private Link tail;
        /**
         * 每一个WeakOrderQueue对象中都会有下一个WeakOrderQueue节点的指针。这个链表实际上是从stack对象中延伸出来的
         * 因为WeakOrderQueue对象就是stack类的一个成员变量，就相当于stack的头节点，头节点正好指向下一个WeakOrderQueue节点
         */
        private WeakOrderQueue next;
        /**
         * 这里可以看到，WeakOrderQueue对象中持有了一个线程，并且使用用弱引用包装的
         * 这里的这个线程并不是原本获取对象池中对象的线程，而是帮助原本线程回收对象的线程
         */
        private final WeakReference<Thread> owner;
        /**
         * 帮助其他线程回收对象的线程的id，每一个WeakOrderQueue都对应着一个帮助回收对象的线程，而每一个这样的线程都对应着一个id
         * 但是大家也应该要注意，一个线程既可以是从对象池中获得对象的线程，也可以是帮助回收对象的线程。都是相对的。
         * -2147483648
         */
        private final int id = ID_GENERATOR.getAndIncrement();

        @SuppressWarnings("serial")
        static final class Link extends AtomicInteger {
            /**
             * link中用来存储待回收对象的容器，是个数组，该数组的容量为16，是默认的，如果数组满了，就会创建新的link对象，添加到link
             * 链表的尾部，这里是尾插法。而WeakOrderQueue对象插入到WeakOrderQueue队列中时是头插法，要区分开
             */
            private final DefaultHandle<?>[] elements = new DefaultHandle[LINK_CAPACITY];
            /**
             * 这个相当于读指针
             */
            private int readIndex;
            /**
             * 链表指针，指向下一个link节点
             */
            Link next;
        }

        static final class Head {
            /**
             * 这个属性就是所有帮忙回收对象的线程能够为该WeakOrderQueue对应的线程回收对象的最大个数
             * 简单来说，就是一个线程有好多个对象要其他线程帮忙回收，那其他帮忙回收的线程可以为该线程回收availableSharedCapacity这么多个对象。这个值是个AtomicInteger对象，是stack中的成员变量
             * 在不同的类中传递，但被final修饰，引用不可变，所以它的值被改变了，引用它的对象的值都会被改变
             * 所以在下面大家会看到它是用cas的方法改变自己的值的，否则会出现并发问题
             * 再强调一遍啊，这个原子对象会在多个WeakOrderQueue对象的head中被使用
             */
            private final AtomicInteger availableSharedCapacity;
            /**
             * link链表的头节点，该头节点在head节点中
             */
            Link link;

            Head(AtomicInteger availableSharedCapacity) {
                this.availableSharedCapacity = availableSharedCapacity;
            }

            @Override
            protected void finalize() throws Throwable {
                try {
                    super.finalize();
                } finally {
                    Link head = link;
                    link = null;
                    while (head != null) {
                        reclaimSpace(LINK_CAPACITY);
                        Link next = head.next;
                        // Unlink to help GC and guard against GC nepotism.
                        head.next = null;
                        head = next;
                    }
                }
            }
            // space为16
            void reclaimSpace(int space) {
                assert space >= 0;
                availableSharedCapacity.addAndGet(space);
            }

            boolean reserveSpace(int space) {
                return reserveSpace(availableSharedCapacity, space);
            }

            /**
             * @param availableSharedCapacity availableSharedCapacity一般是2048
             * @param space                   16
             * @return
             */
            static boolean reserveSpace(AtomicInteger availableSharedCapacity, int space) {
                assert space >= 0;
                // 自旋
                for (; ; ) {
                    // 2048
                    int available = availableSharedCapacity.get();
                    // 如果可帮助的对象个数小于需要的对象个数，就直接返回false
                    if (available < space) {
                        return false;
                    }
                    // 走到这里说明这个线程还可以继续为原本获得对象的线程回收对象，那就减去16
                    if (availableSharedCapacity.compareAndSet(available, available - space)) {
                        return true;
                    }
                }
            }
        }


        private WeakOrderQueue() {
            owner = null;
            head = new Head(null);
        }

        private WeakOrderQueue(Stack<?> stack, Thread thread) {
            // 初始化tail节点
            tail = new Link();
            // 创建头节点
            head = new Head(stack.availableSharedCapacity);
            // 链表中还没有数据，所以暂时让头节点指向尾节点
            head.link = tail;
            // 线程被包装在弱引用当中了
            owner = new WeakReference<Thread>(thread);
        }

        static WeakOrderQueue newQueue(Stack<?> stack, Thread thread) {
            // 创建一个WeakOrderQueue
            final WeakOrderQueue queue = new WeakOrderQueue(stack, thread);
            //还记得之前说的吗？WeakOrderQueue都是头插法插入到WeakOrderQueue链表中的
            //点进去会发现setHead方法是整个类中唯一一个加了锁了方法。因为把WeakOrderQueue对象添加到WeakOrderQueue链表头部
            //很可能是多个线程同时在进行，因为一个线程从对象池中获得的多个对象可能需要多个线程帮其回收，每个帮助回收的
            //线程都对应着一个WeakOrderQueue对象，自然会出现同时把WeakOrderQueue对象添加到头节点的情况
            //这时候就必须用synchronized来防止并发问题的出现
            //注意，这里是stack在调用setHead方法
            stack.setHead(queue);

            return queue;
        }

        private void setNext(WeakOrderQueue next) {
            assert next != this;
            this.next = next;
        }

        /**
         * Allocate a new {@link WeakOrderQueue} or return {@code null} if not possible.
         */
        static WeakOrderQueue allocate(Stack<?> stack, Thread thread) {
            // 首先判断是否还有剩余的可帮助回收的对象的数量，如果数量不够则不创建WeakOrderQueue对象
            return Head.reserveSpace(stack.availableSharedCapacity, LINK_CAPACITY)
                    ? newQueue(stack, thread) : null;
        }

        void add(DefaultHandle<?> handle) {
            // 这里看到lastRecycledId再次登场了，其实就可以把handle看成要被回收的对象，现在该对象内的lastRecycledId被id赋值了
            // 而id就是WeakOrderQueue中的对应的帮助回收的线程的id，这就把我们之前讲的那个给对应上了
            // 现在要被回收的对象中的lastRecycledId是id这个值，这就意味着该对象的回收进度已经进行到一半了，它还未完全被回收
            // 只是放在了帮助它回收的线程中，等它完全被回收的时候，handle中另一个属性recycleId也会被再次赋值，和lastRecycledId相等了
            handle.lastRecycledId = id;
            // 找到link链表的尾节点。就像我们上面说的，从尾节点添加被回收对象，从头节点取走
            Link tail = this.tail;
            // 这个writeIndex其实就可以代表是写指针，表示我们link对象中的数组写到第几位了
            int writeIndex;
            // 尾巴节点的写索引已经到了16了说明要创建新的Link节点了，新的Link节点插入到链表尾部
            if ((writeIndex = tail.get()) == LINK_CAPACITY) {
                // 判断可帮助创建的剩余对象数量还够不够，不够就直接返回
                if (!head.reserveSpace(LINK_CAPACITY)) {
                    return;
                }
                // 创建新的Link然后tail指向它
                this.tail = tail = tail.next = new Link();
                // 新的tail节点的写索引应该是0
                writeIndex = tail.get();
            }
            // 放到新的Link里面
            tail.elements[writeIndex] = handle;
            // 这里有个很有意思的地方，就是可以看到handle中的stack会被置为null，我们知道handle中的stack实际上对应的就是原来线程
            // 的对象池，而这个stack对象内部其实持有者它对应的线程。所以我们可以通过stack这个属性找到对象池所属的线程。
            // 但这里把该属性置为null了。这是考虑到在对象被回收的过程中如果原来对象池对应的线程突然挂掉了，线程挂掉了那对应的
            // stack对象池也就不能再被使用了。所以这里把stack设置为null，是为了消除这个强引用，帮助jvm垃圾回收挂掉的线程对应的stack
            // 但是如果线程没挂掉呢？这里却置为null了，这说明一定有一个地方还会把handle中的stack还原。没错，就是在该对象被转移回自己的stack时还原了
            handle.stack = null;
            // 更新写索引
            tail.lazySet(writeIndex + 1);
        }

        boolean hasFinalData() {
            return tail.readIndex != tail.get();
        }

        // 尽可能多地将队列中的项目转移到堆栈中，如果有项目转移，返回true
        @SuppressWarnings("rawtypes")
        boolean transfer(Stack<?> dst) {
            // 获取当前WeakOrderQueue的Link的头节点
            Link head = this.head.link;
            // 如果Link链表是NULL说明这个里面根本没有帮忙回收的对象返回false即可
            if (head == null) {
                return false;
            }
            // 如果这个节点的读索引已经是16了，说明这个Link节点读取完了应该读取下一个Link节点
            if (head.readIndex == LINK_CAPACITY) {
                // 如果没有下一个节点
                if (head.next == null) {
                    return false;
                }
                // 走到这里说明有下一个Link节点，这里获得下一个Link节点并且赋值给head，说明以前的Link都被读取过了作废了！
                this.head.link = head = head.next;
                // 更新availableSharedCapacity，加16，所有线程帮助回收的对象的总量增加了16
                this.head.reclaimSpace(LINK_CAPACITY);
            }
            // 获取这个head的读索引
            final int srcStart = head.readIndex;
            // 获取这个Link的写索引
            int srcEnd = head.get();
            // 写索引-读索引，是还有多少个可以读
            final int srcSize = srcEnd - srcStart;
            // 如果这个Link内部没有可读的了则返回false
            if (srcSize == 0) {
                return false;
            }
            // 获取Stack中的对象数量
            final int dstSize = dst.size;
            // 未来增加后的Stack的对象数量
            final int expectedCapacity = dstSize + srcSize;
            // 如果计算后的数量 > 对象池的容量，这种判断可以猜测到是数组扩容逻辑
            if (expectedCapacity > dst.elements.length) {
                // 具体的扩容逻辑不用看，也没啥看的必要，扫一眼即可，确保没有其他重要的逻辑即可，如果没有忽略，这种属于工具方法没啥看的必要
                final int actualCapacity = dst.increaseCapacity(expectedCapacity);
                // Link中对象已读数量 + （Stack对象池扩容后的容量 - 当前的Stack中的对象数量 = 剩余的可写容量） = 该Link节点中一共转移走的对象个数综合
                // Link写索引也就是Link中存储元素的个数
                // 这里代表最终可以转移走的对象的数量，不能超过16，说实话有点没太看懂 后面回头再看
                srcEnd = min(srcStart + actualCapacity - dstSize, srcEnd);
            }
            // Link中对象已读数量(已经被转移走的对象数量) != 最终可以转移走的对象数量
            // 读索引 != 写索引，反过来思考他俩相等说明什么？没有可读取的数据
            // 反过来就是什么？有可读取的数据
            if (srcStart != srcEnd) {
                // 获取当前Link的所有Handle
                final DefaultHandle[] srcElems = head.elements;
                // 获取Stack里面的所有Handle
                final DefaultHandle[] dstElems = dst.elements;
                // Stack中的对象数量
                int newDstSize = dstSize;
                // 遍历Link的可读部分
                for (int i = srcStart; i < srcEnd; i++) {
                    // 获取当前的Handle
                    DefaultHandle element = srcElems[i];
                    // 如果这个是0说明该对象确实还没有回收到Stack
                    if (element.recycleId == 0) {
                        // 更新recycleId为lastRecycledId
                        element.recycleId = element.lastRecycledId;
                    } else if (element.recycleId != element.lastRecycledId) {
                        // 该Handle被回收了
                        throw new IllegalStateException("recycled already");
                    }
                    // 帮助GC
                    srcElems[i] = null;
                    // 判断是否达到回收比例
                    if (dst.dropHandle(element)) {
                        // 没有达到就丢弃
                        continue;
                    }
                    // 赋值Stack，在Handle放到线程的WeakOrderQueue的时候Handle内部关联的Stack被清除了，在这里被重新赋值
                    element.stack = dst;
                    // 放入到Stack中
                    dstElems[newDstSize++] = element;
                }
                /*
                 * 前提条件：走到这里已经转移完了这个Link的所有可读数据
                 * 条件1：当前Link写完了，也就是当前Link数据都转移走了
                 * 条件2：不是最后一个Link
                 */
                if (srcEnd == LINK_CAPACITY && head.next != null) {
                    // 这里就可以增加可以帮助回收对象的数量，然后把下一个link节点设置成头节点
                    // 并且帮助垃圾回收
                    this.head.reclaimSpace(LINK_CAPACITY);
                    this.head.link = head.next;
                }
                // 把写指针的值赋给读指针，说明link节点的数据全都读取完了
                head.readIndex = srcEnd;
                // 这里是判断，经过转移后，创建对象的线程的对象池容量有没有变化，是不是还是旧的容量，也就是存储的元素个数没变
                if (dst.size == newDstSize) {
                    return false;
                }
                // 有变化就给size重新赋值
                dst.size = newDstSize;
                return true;
            } else {
                return false;
            }
        }
    }

    static final class Stack<T> {
        /**
         * Recycler对象
         */
        final Recycler<T> parent;
        /**
         * 当前线程
         */
        final WeakReference<Thread> threadRef;
        /**
         * 能够帮助从对象池获得对象的那个线程回收的对象最大值2048
         */
        final AtomicInteger availableSharedCapacity;
        /**
         * 每个线程最多可以帮助几个线程回收它们的对象
         */
        final int maxDelayedQueues;
        /**
         * 线程的stack中数组的最大容量，实际上就是对象池的最大容量
         */
        private final int maxCapacity;
        /**
         * 这个就是每个线程回收自身对象的比例
         */
        private final int ratioMask;
        /**
         * 对象池内部真正存储对象的属性，对象一般会被包装为Handle存进来
         */
        private DefaultHandle<?>[] elements;
        /**
         * 对象池中的对象数量
         */
        private int size;
        /**
         * 这个属性和回收对象比例有关的，要配合ratioMask一起使用
         */
        private int handleRecycleCount = -1;
        /**
         * 定义了当前节点和前驱节点终于看到WeakOrderQueue节点了，stack中既有数组，同时也存在一个WeakOrderQueue对象构成的链表
         */
        private WeakOrderQueue cursor, prev;
        /**
         * WeakOrderQueue头节点
         */
        private volatile WeakOrderQueue head;

        /**
         * @param parent                  Recycler对象
         * @param thread                  当前线程
         * @param maxCapacity             线程的stack中数组的最大容量，实际上就是对象池的最大容量
         * @param maxSharedCapacityFactor 这个属性就是帮助计算所有帮忙回收对象的线程能够为原来获取对象的线程能够回收的对象的最大值
         * @param ratioMask               这个就是每个线程回收自身对象的比例
         * @param maxDelayedQueues        每个线程最多可以帮助几个线程回收它们的对象
         */
        Stack(Recycler<T> parent, Thread thread, int maxCapacity, int maxSharedCapacityFactor,
              int ratioMask, int maxDelayedQueues) {
            this.parent = parent;
            threadRef = new WeakReference<>(thread);
            this.maxCapacity = maxCapacity;
            // 4096/2(2048),16
            availableSharedCapacity = new AtomicInteger(max(maxCapacity / maxSharedCapacityFactor, LINK_CAPACITY));
            elements = new DefaultHandle[min(INITIAL_CAPACITY, maxCapacity)];
            this.ratioMask = ratioMask;
            this.maxDelayedQueues = maxDelayedQueues;
        }

        synchronized void setHead(WeakOrderQueue queue) {
            // 之前解释过，插入WeakOrderQueue头节点的时候是头插法，并且是多个线程一起工作的，所以会存在并发问题
            // 所以在这里用了对象池中唯一的一个锁
            queue.setNext(head);
            head = queue;
        }

        int increaseCapacity(int expectedCapacity) {
            int newCapacity = elements.length;
            int maxCapacity = this.maxCapacity;
            do {
                newCapacity <<= 1;
            } while (newCapacity < expectedCapacity && newCapacity < maxCapacity);

            newCapacity = min(newCapacity, maxCapacity);
            if (newCapacity != elements.length) {
                elements = Arrays.copyOf(elements, newCapacity);
            }

            return newCapacity;
        }

        @SuppressWarnings({"unchecked", "rawtypes"})
        DefaultHandle<T> pop() {
            // 对象池中对象的数量
            int size = this.size;
            // 如果当前对象池中的没有对象了
            if (size == 0) {
                // 这时候就要从其他帮忙回收对象的线程的WeakOrderQueue对象中看看是否有可以转移回来的对象，如果有就转移回来，没有就返回NULL
                if (!scavenge()) {
                    return null;
                }
                // 走到这里说明WeakOrderQueue有数据，转移完成之后重新给size赋值
                size = this.size;
            }
            // 要从Stack中获取一个对象所以减一
            size--;
            // 存储对象的个数减1正好得到数组存储的最后一个对象的数组下标，取出该下标的对象
            DefaultHandle ret = elements[size];
            // 把数组原位置置为null
            elements[size] = null;
            if (ret.lastRecycledId != ret.recycleId) {
                throw new IllegalStateException("recycled multiple times");
            }
            // 刚从对象池拿出来的时候这两个属性都设置为0
            ret.recycleId = 0;
            ret.lastRecycledId = 0;
            // 取走了一个对象，要重新给size赋值
            this.size = size;
            return ret;
        }

        boolean scavenge() {
            // 这一步就是从其他线程的WeakOrderQueue对象中把属于自己对象池的对象移回到自己的stack中
            if (scavengeSome()) {
                return true;
            }

            // 如果所有WeakOrderQueue节点中都没有对象，就把当前节点和前驱节点重新初始化，因为在查找的过程中，这两个值已经发生改变了
            prev = null;
            cursor = head;
            return false;
        }

        boolean scavengeSome() {
            // 前驱节点
            WeakOrderQueue prev;
            // 也定义好当前节点，这时候当前节点还是null
            WeakOrderQueue cursor = this.cursor;
            // 这里会有一个判断，看当前节点是否为null，如果为null，说明是第一次扫描WeakOrderQueue链表
            if (cursor == null) {
                // 设置前驱节点也为NULL，一般这个时候也是NULL
                prev = null;
                // 获取WeakOrderQueue的head，也就是链表头
                cursor = head;
                // 判断head是不是NULL，是NULL说明没有其他线程帮它回收对象，return false代表转移失败
                if (cursor == null) {
                    return false;
                }
            } else {
                prev = this.prev;
            }
            // 走到这里cursor一定不为NULL，这里先是当作head看
            // 成功标记
            boolean success = false;
            do {
                // 调用head节点的transfer方法，传递的对象stack
                // 这个方法之前讲过了吧，可以看之前的逻辑，就是把WeakOrderQueue对象中的
                // 数据转移到当前stack中，一次限定转移一个link中数组的容量，也就是16
                if (cursor.transfer(this)) {
                    // 转移成功标记
                    success = true;
                    // 结束
                    break;
                }
                // 走到这里意味着刚才的那个当前节点中没有可被回收的对象，这时候就找下一个WeakOrderQueue节点查看
                // 所以先得到当前节点的下一个节点
                WeakOrderQueue next = cursor.next;
                // 这里要判断一下当前节点所对应的线程是不是已经挂掉了
                // 注意，这里当前节点对应的是帮助回收对象的线程
                if (cursor.owner.get() == null) {
                    // 如果真的挂掉了，就判断当前节点中是否还有未被转移到stack的数据
                    // 内部逻辑就是判断读写所以是否不一样，只要读写索引不一样就还有数据
                    if (cursor.hasFinalData()) {
                        // 自旋转移这个WeakOrderQueue的所有数据
                        for (; ; ) {
                            // 如果有，就把所有数据都回收一下，这里是循环回收，并不是只回收一次
                            if (cursor.transfer(this)) {
                                // 只要转移了就设置成功标记
                                success = true;
                            } else {
                                break;
                            }
                        }
                    }

                    if (prev != null) {
                        prev.setNext(next);
                    }
                } else {
                    // 走到这里说明帮助回收对象的线程没有挂掉，把WeakOrderQueue当前节点保存到prev中
                    prev = cursor;
                }
                // 把next节点保存至cursor
                cursor = next;
            // 退出条件
            } while (cursor != null && !success);
            // 转移完了之后，给改变了的当前节点和前驱节点赋值
            this.prev = prev;
            this.cursor = cursor;
            return success;
        }

        void push(DefaultHandle<?> item) {
            // 获取当前线程
            Thread currentThread = Thread.currentThread();
            // 判断当前线程和对象池的持有线程是不是一个，如果是直接放回到对象池中即可
            if (threadRef.get() == currentThread) {
                pushNow(item);
            } else {
                // 不是则说明是其他线程帮忙回收的，那就放到其他线程对应的WeakOrderQueue对象中即可
                // 注意：既然走到这里，也就说明执行当前方法的线程已经是帮忙回收对象的线程了
                // 这个currentThread参数就是帮忙回收对象的线程。所以才有了后来每一个帮忙回收对象的线程都有一个WeakOrderQueue对象
                pushLater(item, currentThread);
            }
        }

        private void pushNow(DefaultHandle<?> item) {
            /*
             * 已经回收的判断逻辑
             * 条件成立：就是已经回收过了或者正在回收
             * 如果线程回收自己对象池中的对象，那么Handle中的这两个属性都还是0，是相等的
             * 其中有一个不等于0就说明已经被回收了，或者至少放在WakeOrderQueue了
             */
            if ((item.recycleId | item.lastRecycledId) != 0) {
                throw new IllegalStateException("recycled already");
            }
            // 走到这里说明这个对象没有回收过
            // 把OWN_THREAD_ID赋值给lastRecycledId与recycleId
            // 因为是当前线程回收对象所以这个两个值是相等的（recycleId，lastRecycledId）
            // 这两个值一致说明当前Handle被回收掉了
            item.recycleId = item.lastRecycledId = OWN_THREAD_ID;
            // 获得对象池中的数量
            int size = this.size;
            // 如果对象池容量已经达到上限 或者 没有达到回收比例
            // 不进行回收了直接返回
            if (size >= maxCapacity || dropHandle(item)) {
                return;
            }
            // 对象池数组扩容逻辑，条件是对象池当前数量已经达到了数组最大容量
            if (size == elements.length) {
                // 扩容至两倍
                elements = Arrays.copyOf(elements, min(size << 1, maxCapacity));
            }
            // 放入到对象池中就是回收了
            elements[size] = item;
            // 更新size
            this.size = size + 1;
        }

        private void pushLater(DefaultHandle<?> item, Thread thread) {
            // FastThreadLocal保存的WeakHashMap
            // Key是该线程帮忙回收对象线程所拥有的stack，value就是该线程自己的WeakOrderQueue
            Map<Stack<?>, WeakOrderQueue> delayedRecycled = DELAYED_RECYCLED.get();
            // 根据Stack获取WeakOrderQueue
            WeakOrderQueue queue = delayedRecycled.get(this);
            // 第一次帮助这个线程回收对象WeakOrderQueue是NULL就去创建
            if (queue == null) {
                // 每个线程能帮忙回收的线程数量是由最大值的，超过最大值肯定就不行了
                // 怎么知道当前线程目前帮助了几个线程进行回收呢，就是delayedRecycled的size即可，只要size>=maxDelayedQueues就不帮忙回收了
                if (delayedRecycled.size() >= maxDelayedQueues) {
                    // 把stack和一个标识对象添进去
                    // 这个WeakOrderQueue.DUMMY属性，如果WeakOrderQueue链表中的一个对象是这个，就不会帮助回收对象
                    delayedRecycled.put(this, WeakOrderQueue.DUMMY);
                    return;
                }
                // 走到这里说明当前线程帮助其他线程回收对象的线程数量没有达到最大值
                // 创建一个WeakOrderQueue并且把被绑住回收线程的对象池和当前线程传进来
                // 这里就真正为帮助回收的线程创建了一个WeakOrderQueue，然后加入到stack中WeakOrderQueue链表的头节点处
                if ((queue = WeakOrderQueue.allocate(this, thread)) == null) {
                    return;
                }
                // 放入到Map中
                delayedRecycled.put(this, queue);
            } else if (queue == WeakOrderQueue.DUMMY) {
                // 走到这里就意味着queue不为null，但是为WeakOrderQueue.DUMMY
                // 这也表示该WeakOrderQueue.DUMMY不会帮助回收对象
                return;
            }
            // 把Handle放到WeakOrderQueue中
            queue.add(item);
        }

        boolean dropHandle(DefaultHandle<?> handle) {
            // 先判断对象是否已经被回收了，这里判断的是没有被回收
            if (!handle.hasBeenRecycled) {
                // 默认值是-1自增1后是0所以返回的肯定是0（0和任何一个数&都等于0，所以一定不会返回true），所以第一次回收对象的时候，该对象一定可以被回收
                // 说白了就是判断是不是8的倍数，是8的倍数的时候才进行一次回收，不是8的倍数的时候就不进行回收
                if ((++handleRecycleCount & ratioMask) != 0) {
                    return true;
                }
                // 因为后面要走回收逻辑所以这设置为被回收了
                handle.hasBeenRecycled = true;
            }
            return false;
        }

        /**
         * 创建一个Handle
         *
         * @return
         */
        DefaultHandle<T> newHandle() {
            return new DefaultHandle<T>(this);
        }
    }
}
